const { electron } = require("process");

module.exports = GCodeDriver;

// 用于优化 GCode 文件： 1. 合并相邻的 G0/G1 指令 2. 将 S 指令追加到 G0/G1 命令中
const LAST_CMD_G0 = 1;
const LAST_CMD_G1 = 2;
const LAST_CMD_LASER = 3;
const LAST_CMD_OTHER = 4;

function GCodeDriver(stream, opt) {
  this.stream = stream || {
    write: function (str) {
      console.log(str);
    }
  };
  this.lastLineCmdMode = LAST_CMD_OTHER; // 记录上一个命令模式
  this.cacheCmd = ''; // 缓存命令，用于将 S 值追加到 G0/G1 命令中
  this.previewMode = false;
  this.frequency = 30;
  this.swapXY = false;
  if (opt && opt.swapXY){
    this.swapXY = true;
  }
}

GCodeDriver.prototype = {
  send: function (code, params, extra) {
    var command = code;

    if (!command) return;

    if (command === 'omit') {
      command = '';
    }
    
    let swapXY = this.swapXY;

    if (params) {
      'xyzabcijkf'.split('').forEach(function (k) {
        if (params[k] === undefined || params[k] === null)
          return;
        params[k] = Math.round(params[k] * 1000) / 1000;
        if (k === 'x' && swapXY) {
          command += 'Y' + params[k];
        } else if (k === 'y' && swapXY) {
          command += 'X' + params[k];
        } else {
          command += k.toUpperCase() + params[k];
        }
      });
    }

    if (extra) {
      command += extra;
    }

    this.stream.write(command);
  }
  , setPreviewMode: function (mode) {
    this.previewMode = mode;
  }
  , setFrequency: function (freq) {
    this.frequency = freq || this.frequency;
  }
  , init: function () {
    this.send('G00'); // 下位机的程序开始标志
    this.send('G90'); // 绝对位置
    // this.feed(); // 设置进给速度
    if (!this.previewMode) {
      this.laserOn(); // 打开激光头
    }
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  , unit: function (name) {
    name = name.toLowerCase();
    this.send({ 'inch': 'G20', 'mm': 'G21' }[name]);
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  , speed: function (n) {
    // this.send('S'+n);
    if (this.cacheCmd === '') {
      this.cacheCmd = 'S' + n;
    } else if (this.cacheCmd.startsWith('S')) { // 连续两个功率值
      // 打点模式下，先 SO 再开 实际值
      this.send(this.cacheCmd);
      this.cacheCmd = 'S' + n;
    } else { 
      this.send('S' + n);
    }
    this.lastLineCmdMode = LAST_CMD_LASER;
  }
  , feed: function (n) {
    this.send('F' + n);
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  , freq : function() {
    // TODO: 设置激光频率
    this.send('KA'+ this.frequency);
  }
  , onLightDelay: function (delay) {
    this.send('KB' + delay);
  }
  , offLightDelay: function (delay) {
    this.send('KC' + delay);
  }
  , jumpDelay: function (delay) {
    this.send('KD' + delay);
  }
  , cornerDelay: function (delay) {
    this.send('KE' + delay);
  }
  , version: function(version) {
    this.send('KV'+ version)
  }
  , coolant: function (type) {
    if (type === 'mist') {
      // special
      this.send('M7');
    }
    else if (type) {
      // flood
      this.send('M8');
    }
    else {
      // off
      this.send('M9');
    }
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  , zero: function (params) {
    this.send('G28.3', params);
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  , finishProgram: function () {
    this.send('M2');
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  , laserOn: function () {
    this.send('M4');
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  , laserOff: function () {

    this.send('M5');
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  // , laserPower: function(power) {
  //     this.send('S'+power);
  //   }
  , atc: function (id) {
    this.send('M6', { T: id });
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  , rapid: function (params) {
    if (this.lastLineCmdMode === LAST_CMD_G0) {
      this.send('G0', params);
    } else if (this.lastLineCmdMode === LAST_CMD_LASER) {
      this.send('G0', params, this.cacheCmd);
      this.cacheCmd = '';
    } else {
      this.send('G0', params);
    }
    this.lastLineCmdMode = LAST_CMD_G0;
  }
  , linear: function (params) {
    if (this.lastLineCmdMode === LAST_CMD_G1) {
      this.send('omit', params);
    } else if (this.lastLineCmdMode === LAST_CMD_LASER) {
      this.send('G1', params, this.cacheCmd);
      this.cacheCmd = '';
    } else {
      this.send('G1', params);
    }
    this.lastLineCmdMode = LAST_CMD_G1;
  }
  , arcCW: function (params) {
    this.send('G2', params);
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  , arcCCW: function (params) {
    this.send('G3', params);
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  , meta: function (params) {
    var comment = '(';
    for (var k in params) {
      comment += k + '=' + params[k];
    }
    comment += ')';

    this.send(comment);
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
  , saveFile: function (filename) {
    this.send('M20', { S: filename });
    this.lastLineCmdMode = LAST_CMD_OTHER;
  }
};
